package com.malcom.library.android.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.util.Log;
import com.malcom.library.android.MCMDefines;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import static android.content.Context.LOCATION_SERVICE;
public class LocationUtils {
public static final String RECONSTRUCTION_PROVIDER = "reconstruction";
private static final String PREFERENCES_NAME = "com.malcom.location";
private static final String LATITUDE_KEY = "location.latitude";
private static final String LONGITUDE_KEY = "location.longitude";
public static String getDeviceCityLocation(Context context) {
String res = "";
Location lastKnownLocation = getLocation(context);
//lastKnowLocation could be null, so instead of throw an NPE return an empty String
if ( lastKnownLocation == null )
return res;
try {
Geocoder gcd = new Geocoder(context, Locale.getDefault());
List<Address> addresses = gcd.getFromLocation(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude(), 1);
if (addresses.size() > 0) {
res = addresses.get(0).getLocality();
}
} catch (IOException e) {
Log.e(MCMDefines.LOG_TAG,"Error getting city location: "+e.getMessage());
} catch (NullPointerException npe) {
Log.e(MCMDefines.LOG_TAG,"Error getting city location: "+npe.getMessage());
}
return res;
}
/**
* Gets the most accurate {@link Location} from the enabled providers
* or tries to reconstruct it from latitude and longitude coordinates stored in shared preferences.
*
* In case the {@link Location} is reconstructed its provider will be {@link #RECONSTRUCTION_PROVIDER} and
* it will only have values for latitude and longitude. The other values will be defaults.
*
* Returns null if location is not available anywhere.
*/
public static Location getLocation(Context context)
{
return findMostAccurateLastKnownLocation(context);
}
public static JSONObject getLocationJson(Context context) {
JSONObject locationJson = new JSONObject();
Location lastKnownLocation = getLocation(context);
try {
if (lastKnownLocation != null)
{
Float accuracy = new Float(lastKnownLocation.getAccuracy());
locationJson.put("accuracy", accuracy.longValue());
locationJson.put("latitude", lastKnownLocation.getLatitude());
locationJson.put("longitude", lastKnownLocation.getLongitude());
} else
{
locationJson.put("accuracy", 0);
locationJson.put("latitude", 0);
locationJson.put("longitude", 0);
}
} catch (JSONException e) {
Log.i(MCMDefines.LOG_TAG, "JSONException = " + e.getMessage());
}
return locationJson;
}
/**
* Tries to find the most accurate 'lastKnownLocation', or returns null if none is found.
*
* Searches all providers for the most accurate 'lastKnownLocation' and, if not found,
* retrieves the last location retrieved (which is stored in the shared preferences).
*/
public static Location findMostAccurateLastKnownLocation(Context context)
{
LocationManager locationManager = (LocationManager) context.getSystemService( LOCATION_SERVICE );
List<String> providers = locationManager.getProviders(true);
Location best = null;
for (String provider : providers)
{
Location current = locationManager.getLastKnownLocation(provider);
if (current != null && (best == null || current.getAccuracy() > best.getAccuracy()))
best = current;
}
if (best == null)
best = getLocationFromSharedPreferences(context);
else
storeLocationInSharedPreferences(best, context);
return best;
}
/**
* Tries to reconstruct the latest location from coordinates stored in the shared preferences.
* Returns null if the location coordinates are not found in the shared preferences.
*/
private static Location getLocationFromSharedPreferences(Context context)
{
final SharedPreferences prefs =
context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
if (prefs.contains(LATITUDE_KEY) && prefs.contains(LONGITUDE_KEY))
{
double latitude = PreferencesUtils.getDouble(prefs, LATITUDE_KEY, 0L);
double longitude = PreferencesUtils.getDouble(prefs, LONGITUDE_KEY, 0L);
Location reconstructedLocation = new Location(RECONSTRUCTION_PROVIDER);
reconstructedLocation.setLatitude(latitude);
reconstructedLocation.setLongitude(longitude);
return reconstructedLocation;
} else {
return null;
}
}
private static void storeLocationInSharedPreferences(Location location, Context context) {
final SharedPreferences prefs =
context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
PreferencesUtils.putDouble(editor, LATITUDE_KEY, location.getLatitude());
PreferencesUtils.putDouble(editor, LONGITUDE_KEY, location.getLongitude());
editor.commit();
}
}